
#ifndef __COMMON_H__
#define __COMMON_H__


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <math.h>
#include <sys/time.h>

#define MAX_COMMAND_LENGTH 16
#define AUTOMATED_FILENAME 512
typedef unsigned char uchar_t;

//System configuration information
struct SysConfig_t
{
    float drop_prob;
    float corrupt_prob;
    unsigned char automated;
    char automated_file[AUTOMATED_FILENAME];
};
typedef struct SysConfig_t  SysConfig;

//Command line input information
struct Cmd_t
{
    uint16_t src_id;
    uint16_t dst_id;
    char * message;
};
typedef struct Cmd_t Cmd;

//Linked list information
//用于标记链表节点中存储的值的类型。
enum LLtype 
{
    llt_string,
    llt_frame,
    llt_integer,
    llt_head
};

//它的作用是为发送方和接收方维护一个灵活的数据结构，用于存储和操作消息、帧或其他类型的数据
typedef struct LLnode_t {
    struct LLnode_t * prev;
    struct LLnode_t * next;
    void * value;                 //可以存储任何的数据，但是在转化的时候应该转化成对于的数据类型
} LLnode;


//Receiver and sender data structures
struct Receiver_t
{
    pthread_mutex_t buffer_mutex;
    pthread_cond_t buffer_cv;
    LLnode input_framelist_head;

    int recv_id;
    // 新增字段：期望的序列号
};

struct Sender_t
{
    pthread_mutex_t buffer_mutex;
    pthread_cond_t buffer_cv;    
    LLnode input_cmdlist_head;   //存储发送出去的
    LLnode input_framelist_head; //双向链表最好有个头结点
    int send_id;
};

enum SendFrame_DstType 
{
    ReceiverDst,
    SenderDst
};

typedef struct Sender_t Sender;
typedef struct Receiver_t Receiver;




#define WINDOW_SIZE 10  //滑动窗口的大小

//TODO: You should change this!
//Remember, your frame can be AT MOST 32 bytes!

#define MAX_FRAME_SIZE 64
#define HEADER_SIZE 7  // 1字节序列号 + 1字节确认号 + 1字节ACK标志 + 2字节校验和
#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - HEADER_SIZE) // 数据部分最多59字节
struct Frame_t
{
    uint8_t seq_num;                     // 序列号 (1 字节)
    uint8_t ack_num;                     // 确认号 (1 字节)
    uint8_t is_ack;                      // ACK 标志 (1 字节，0=数据帧，1=确认帧)
    uint16_t checksum;                   // 校验和 (2 字节)
    uint8_t send_id;                    // 发送方ID (1字节)
    uint8_t recv_id;                    // 接收方ID (1字节)
    char data[FRAME_PAYLOAD_SIZE];       // 数据负载 (最多 57 字节)
};
typedef struct Frame_t Frame;


//定义一个单个窗口的结构体，用来存储正在发送但是未确定的帧信息单元
typedef struct WindowEntry_t {
    Frame *frame;                // 保存未确认的帧
    char *charbuf;               // 帧的字节流表示
    uint8_t monitor;
    uint8_t handle;
    struct timeval send_time;    // 记录发送时间
} WindowEntry;

//定义一个结构体来管理整个滑动窗口，用于存储管理当前窗口的帧队列以及窗口的大小
typedef struct SlidingWindow_t {
    WindowEntry *head;           // 滑动窗口的头部
    WindowEntry *tail;           // 滑动窗口的尾部
    int max_size;                // 窗口的最大大小
    int current_size;            // 当前窗口中的帧数量
} SlidingWindow;

// 定义一个全局的滑动窗口映射，假设最多有 10 个发送方
extern SlidingWindow *sliding_windows[10];

//Declare global variables here
//DO NOT CHANGE: 
//   1) glb_senders_array
//   2) glb_receivers_array
//   3) glb_senders_array_length
//   4) glb_receivers_array_length
//   5) glb_sysconfig
//   6) CORRUPTION_BITS

extern Sender * glb_senders_array;
extern  Receiver * glb_receivers_array;
extern int glb_senders_array_length;
extern  int glb_receivers_array_length;
extern SysConfig glb_sysconfig;
extern int CORRUPTION_BITS; 
#endif 
